home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / filesys.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-30  |  32.9 KB  |  1,318 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corp.
  4. All rights reserved.
  5. */
  6.  
  7. /*
  8.  * various file system interface things
  9.  */
  10.  
  11. #include "mint.h"
  12.  
  13. #define PATH2COOKIE_DB(x) TRACE(x)
  14.  
  15. FILESYS *active_fs;
  16. FILESYS *drives[NUM_DRIVES];
  17. extern FILESYS tos_filesys;    /* declaration needed for debugging only */
  18.  
  19. /* "aliased" drives are different names
  20.  * for real drives/directories
  21.  * if drive d is an alias for c:\usr,
  22.  * then alias_drv[3] == 2 (the real
  23.  * drive) and aliases has bit (1L << 3)
  24.  * set.
  25.  * NOTE: if aliasdrv[d] is 0, then d is not an aliased drive,
  26.  * otherwise d is aliased to drive aliasdrv[d]-1
  27.  * (e.g. if drive A: is aliased to B:\FOO, then
  28.  * aliasdrv[0] == 'B'-'A'+1 == 2). Always remember to
  29.  * compensate for the extra 1 when dereferencing aliasdrv!
  30.  */
  31. int    aliasdrv[NUM_DRIVES];
  32.  
  33. FILEPTR *flist;        /* a list of free file pointers */
  34.  
  35. /* vector of valid drives, according to GEMDOS */
  36. /* note that this isn't necessarily the same as what the BIOS thinks of
  37.  * as valid
  38.  */
  39. long dosdrvs;
  40.  
  41. /*
  42.  * Initialize a specific drive. This is called whenever a new drive
  43.  * is accessed, or when media change occurs on an old drive.
  44.  * Assumption: at this point, active_fs is a valid pointer
  45.  * to a list of file systems.
  46.  */
  47.  
  48. /* table of processes holding locks on drives */
  49. extern PROC *dlockproc[];    /* in dosdir.c */
  50.  
  51. void
  52. init_drive(i)
  53.     int i;
  54. {
  55.     long r;
  56.     FILESYS *fs;
  57.     fcookie root_dir;
  58.  
  59.     TRACE(("init_drive(%c)", i+'A'));
  60.  
  61.     drives[i] = 0;        /* no file system */
  62.     if (i >= 0 && i < NUM_DRIVES) {
  63.         if (dlockproc[i]) return;
  64.     }
  65.  
  66.     for (fs = active_fs; fs; fs = fs->next) {
  67.         r = (*fs->root)(i, &root_dir);
  68.         if (r == 0) {
  69.             drives[i] = root_dir.fs;
  70.             release_cookie(&root_dir);
  71.             break;
  72.         }
  73.     }
  74. }
  75.  
  76. /*
  77.  * initialize the file system
  78.  */
  79.  
  80. #define NUMFPS    40    /* initial number of file pointers */
  81.  
  82. void
  83. init_filesys()
  84. {
  85.     static FILEPTR initial[NUMFPS+1];
  86.     int i;
  87.     extern FILESYS tos_filesys, bios_filesys, pipe_filesys,
  88.         proc_filesys, uni_filesys;
  89.  
  90. /* get the vector of connected GEMDOS drives */
  91.     dosdrvs = Dsetdrv(Dgetdrv()) | drvmap();
  92.  
  93. /* set up some initial file pointers */
  94.     for (i = 0; i < NUMFPS; i++) {
  95.         initial[i].devinfo = (ulong) (&initial[i+1]);
  96.     }
  97.     initial[NUMFPS].devinfo = 0;
  98.     flist = initial;
  99.  
  100. /* set up the file systems */
  101.     tos_filesys.next = 0;
  102.     bios_filesys.next = &tos_filesys;
  103.     pipe_filesys.next = &bios_filesys;
  104.     proc_filesys.next = &pipe_filesys;
  105.     uni_filesys.next = &proc_filesys;
  106.  
  107.     active_fs = &uni_filesys;
  108.  
  109. /* initialize the BIOS file system */
  110.     biosfs_init();
  111.  
  112. /* initialize the unified file system */
  113.     unifs_init();
  114. }
  115.  
  116. /*
  117.  * load file systems from disk
  118.  * this routine is called after process 0 is set up, but before any user
  119.  * processes are run
  120.  *
  121.  * NOTE that a number of directory changes take place here: we look first
  122.  * in the current directory, then in the directory \mint.
  123.  */
  124.  
  125. typedef FILESYS * ARGS_ON_STACK (*FSFUNC) P_((struct kerinfo *));
  126.  
  127. /* uk: made this lie outside of functions, as load_filesys() and
  128.  *     load_devdriver() need access to it.
  129.  */
  130. #define NPATHS 3
  131. static const char *const ext_paths[NPATHS] = {"", "\\MINT", "\\MULTITOS"};
  132.  
  133. void
  134. load_filesys()
  135. {
  136.     long r;
  137.     BASEPAGE *b;
  138.     FILESYS *fs;
  139.     FSFUNC initf;
  140.     static DTABUF dta;
  141.     int i;
  142.     extern struct kerinfo kernelinfo; /* in main.c */
  143.     char curpath[PATH_MAX];
  144.     MEMREGION *xfsreg;
  145.  
  146.     curproc->dta = &dta;
  147.     d_getpath(curpath,0);
  148.  
  149.     for (i = 0; i < NPATHS; i++) {
  150.         if (*ext_paths[i]) {
  151. /* don't bother checking the current directory twice! */
  152.             if (!stricmp(ext_paths[i],curpath))
  153.             r = -1;
  154.             else
  155.             r = d_setpath(ext_paths[i]);
  156.         }
  157.         else
  158.             r = 0;
  159.  
  160.         if (r == 0)
  161.             r = f_sfirst("*.xfs", 0);
  162.  
  163.         while (r == 0) {
  164.         b = (BASEPAGE *)p_exec(3, dta.dta_name, (char *)"", (char *)0);
  165.         if ( ((long)b) < 0 ) {
  166.             DEBUG(("Error loading file system %s", dta.dta_name));
  167.             r = f_snext();
  168.             continue;
  169.         }
  170.     /* we leave a little bit of slop at the end of the loaded stuff */
  171.         m_shrink(0, (virtaddr)b, 512 + b->p_tlen + b->p_dlen + b->p_blen);
  172.         initf = (FSFUNC)b->p_tbase;
  173.         TRACE(("initializing %s", dta.dta_name));
  174.         fs = (*initf)(&kernelinfo);
  175.  
  176.         if (fs) {
  177.             TRACE(("%s loaded OK", dta.dta_name));
  178.     /* put the loaded XFS into super accesible memory */
  179.             xfsreg = addr2region( (long) b );
  180.             mark_region(xfsreg, PROT_S);
  181.  
  182.     /* link it into the list of drivers */
  183.     /* uk: but only if it has not installed itself via Dcntl()
  184.      *     after checking if file system is already installed,
  185.      *     so we know for sure that each file system in at most
  186.      *     once in the chain (important for removal!)
  187.      * also note: this doesn't preclude loading two different
  188.      * instances of the same file system driver, e.g. it's perfectly
  189.      * OK to have a "cdromy1.xfs" and "cdromz2.xfs"; the check below
  190.      * just makes sure that a given instance of a file system is
  191.      * installed at most once. I.e., it prevents cdromy1.xfs from being
  192.      * installed twice.
  193.      */
  194.             if ((FILESYS*)1L != fs) {
  195.                 FILESYS *f = active_fs;
  196.                 for (;  f;  f = f->next)
  197.                     if (f == fs)
  198.                         break;
  199.                 if (!f) {   /* we ran completly through the list */
  200.                     fs->next = active_fs;
  201.                     active_fs = fs;
  202.                 }
  203.             }
  204.         } else {
  205.             DEBUG(("%s returned null", dta.dta_name));
  206.             m_free((virtaddr)b);
  207.         }
  208.         r = f_snext();
  209.         }
  210.     }
  211.  
  212. #if 0
  213. /* here, we invalidate all old drives EXCEPT for ones we're already using (at
  214.  * this point, only the bios devices should be open)
  215.  * this gives newly loaded file systems a chance to replace the
  216.  * default tosfs.c
  217.  */
  218.     for (i = 0; i < NUM_DRIVES; i++) {
  219.         if (d_lock(1, i) == 0)    /* lock if possible */
  220.             d_lock(0, i);    /* and then unlock */
  221.     }
  222. #endif
  223. }
  224.  
  225.  
  226. /*
  227.  * uk: load device driver in files called *.xdd (external device driver)
  228.  *     from disk
  229.  * maybe this should go into biosfs.c ??
  230.  *
  231.  * this routine is called after process 0 is set up, but before any user
  232.  * processes are run, but before the loadable file systems come in,
  233.  * so they can make use of external device drivers
  234.  *
  235.  * NOTE that a number of directory changes take place here: we look first
  236.  * in the current directory, then in the directory \mint, and finally
  237.  * the d_lock() calls force us into the root directory.
  238.  * ??? what d_lock() calls ???
  239.  */
  240.  
  241. typedef DEVDRV * ARGS_ON_STACK (*DEVFUNC) P_((struct kerinfo *));
  242.  
  243. #define DEV_SELFINST  ((DEVDRV*)1L)  /* dev driver did dcntl() already */
  244.  
  245. void
  246. load_devdriver()
  247. {
  248.     long r;
  249.     BASEPAGE *b;
  250.     DEVDRV *dev;
  251.     DEVFUNC initf;
  252.     struct dev_descr the_dev;
  253.     static DTABUF dta;
  254.     int i;
  255.     extern struct kerinfo kernelinfo; /* in main.c */
  256.     char curpath[PATH_MAX];
  257.     char dev_name[PATH_MAX];  /* a bit long, but one never knows... */
  258.     char ch, *p;
  259.     MEMREGION *xddreg;
  260.  
  261.  
  262.     curproc->dta = &dta;
  263.     d_getpath(curpath,0);
  264.  
  265.     for (i = 0; i < NPATHS; i++) {
  266.         if (*ext_paths[i]) {
  267. /* don't bother checking the current directory twice! */
  268.             if (!stricmp(ext_paths[i],curpath))
  269.             r = -1;
  270.             else
  271.             r = d_setpath(ext_paths[i]);
  272.         }
  273.         else
  274.             r = 0;
  275.  
  276.         if (r == 0)
  277.             r = f_sfirst("*.xdd", 0);
  278.  
  279.         while (r == 0) {
  280.         b = (BASEPAGE *)p_exec(3, dta.dta_name, (char *)"", (char *)0);
  281.         if ( ((long)b) < 0 ) {
  282.             DEBUG(("Error loading device driver %s", dta.dta_name));
  283.             r = f_snext();
  284.             continue;
  285.         }
  286.     /* we leave a little bit of slop at the end of the loaded stuff */
  287.         m_shrink(0, (virtaddr)b, 512 + b->p_tlen + b->p_dlen + b->p_blen);
  288.         initf = (DEVFUNC)b->p_tbase;
  289.         TRACE(("initializing %s", dta.dta_name));
  290.         dev = (*initf)(&kernelinfo);
  291.  
  292.         if (dev) {
  293.             if (DEV_SELFINST != dev) {
  294.     /* we need to install the device driver ourselves */
  295.                 the_dev.driver = dev;
  296.                 the_dev.dinfo = 0;
  297.                 the_dev.flags = 0;
  298.                 the_dev.tty = (struct tty*)0L;
  299.                 the_dev.reserved[0] = the_dev.reserved[1] = 0;
  300.                 the_dev.reserved[2] = 0;
  301.                 p = dta.dta_name;
  302.     /* copy the dev. driver name, converting to lower case */
  303.                 while (*p && *p != '.') {
  304.                     *p = tolower(*p);
  305.                     p++;
  306.                 }
  307.                 ch = *p;
  308.                 *p = '\0';  /* we dont want the extension */
  309.                 strcpy(dev_name, "u:\\dev\\");
  310.                 strcat(dev_name, dta.dta_name);
  311.                 *p = ch;
  312.                 r = d_cntl(DEV_INSTALL, dev_name, (long)&the_dev);
  313.                 if (r <= 0) {
  314.                     DEBUG(("Error installing device driver %s", dta.dta_name));
  315.                     r = f_snext();
  316.                     continue;
  317.                 }
  318.             }
  319.             TRACE(("%s loaded OK", dta.dta_name));
  320.     /* put the loaded XDD into super accesible memory */
  321.             xddreg = addr2region( (long) b );
  322.             mark_region(xddreg, PROT_S);
  323.         } else {
  324.             DEBUG(("%s returned null", dta.dta_name));
  325.             m_free((virtaddr)b);
  326.         }
  327.         r = f_snext();
  328.         }
  329.     }
  330. }
  331.  
  332.  
  333. void
  334. close_filesys()
  335. {
  336.     PROC *p;
  337.     FILEPTR *f;
  338.     int i;
  339.  
  340.     TRACE(("close_filesys"));
  341. /* close every open file */
  342.     for (p = proclist; p; p = p->gl_next) {
  343.         for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  344.             if ( (f = p->handle[i]) != 0) {
  345.                 if (p->wait_q == TSR_Q || p->wait_q == ZOMBIE_Q)
  346.                     ALERT("Open file for dead process?");
  347.                 do_pclose(p, f);
  348.             }
  349.         }
  350.     }
  351. }
  352.  
  353. /*
  354.  * "media change" routine: called when a media change is detected on device
  355.  * d, which may or may not be a BIOS device. All handles associated with
  356.  * the device are closed, and all directories invalidated. This routine
  357.  * does all the dirty work, and is called automatically when
  358.  * disk_changed detects a media change.
  359.  */
  360.  
  361. void ARGS_ON_STACK 
  362. changedrv(d)
  363.     unsigned d;
  364. {
  365.     PROC *p;
  366.     int i;
  367.     FILEPTR *f;
  368.     FILESYS *fs;
  369.     SHTEXT *stext, **old;
  370.     extern SHTEXT *text_reg;    /* in mem.c */
  371.     DIR *dirh;
  372.     fcookie dir;
  373.     int warned = (d & 0xf000) == PROC_RDEV_BASE;
  374.     long r;
  375.  
  376. /* if an aliased drive, change the *real* device */
  377.     if (d < NUM_DRIVES && aliasdrv[d]) {
  378.         d = aliasdrv[d] - 1;    /* see NOTE above */
  379.     }
  380.  
  381. /* re-initialize the device, if it was a BIOS device */
  382.     if (d < NUM_DRIVES) {
  383.         fs = drives[d];
  384.         if (fs) {
  385.             (void)(*fs->dskchng)(d);
  386.         }
  387.         init_drive(d);
  388.     }
  389.  
  390.     for (p = proclist; p; p = p->gl_next) {
  391.     /* invalidate all open files on this device */
  392.         for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  393.             if (((f = p->handle[i]) != 0) &&
  394.                 (f != (FILEPTR *)1) && (f->fc.dev == d)) {
  395.                 if (!warned) {
  396.                 ALERT(
  397. "Files were open on a changed drive (0x%x)!", d);
  398.                 warned++;
  399.                 }
  400.  
  401. /* we set f->dev to NULL to indicate to do_pclose that this is an
  402.  * emergency close, and that it shouldn't try to make any
  403.  * calls to the device driver since the file has gone away
  404.  */
  405.                 f->dev = NULL;
  406.                 (void)do_pclose(p, f);
  407. /* we could just zero the handle, but this could lead to confusion if
  408.  * a process doesn't realize that there's been a media change, Fopens
  409.  * a new file, and gets the same handle back. So, we force the
  410.  * handle to point to /dev/null.
  411.  */
  412.                 p->handle[i] =
  413.                 do_open("U:\\DEV\\NULL", O_RDWR, 0, (XATTR *)0);
  414.             }
  415.         }
  416.  
  417.     /* terminate any active directory searches on the drive */
  418.         for (i = 0; i < NUM_SEARCH; i++) {
  419.             dirh = &p->srchdir[i];
  420.             if (p->srchdta[i] && dirh->fc.fs && dirh->fc.dev == d) {
  421.                 TRACE(("closing search for process %d", p->pid));
  422.                 release_cookie(&dirh->fc);
  423.                 dirh->fc.fs = 0;
  424.                 p->srchdta[i] = 0;
  425.             }
  426.         }
  427.  
  428.         for (dirh = p->searches; dirh; dirh = dirh->next) {
  429.             /* If this search is on the changed drive, release
  430.                the cookie, but do *not* free it, since the
  431.                user could later call closedir on it. */
  432.             if (dirh->fc.fs && dirh->fc.dev == d) {
  433.                 release_cookie (&dirh->fc);
  434.                 dirh->fc.fs = 0;
  435.             }
  436.         }
  437.             
  438.         if (d >= NUM_DRIVES) continue;
  439.  
  440.     /* change any active directories on the device to the (new) root */
  441.         fs = drives[d];
  442.         if (fs) {
  443.             r = (*fs->root)(d, &dir);
  444.             if (r != E_OK) dir.fs = 0;
  445.         } else {
  446.             dir.fs = 0; dir.dev = d;
  447.         }
  448.  
  449.         for (i = 0; i < NUM_DRIVES; i++) {
  450.             if (p->root[i].dev == d) {
  451.                 release_cookie(&p->root[i]);
  452.                 dup_cookie(&p->root[i], &dir);
  453.             }
  454.             if (p->curdir[i].dev == d) {
  455.                 release_cookie(&p->curdir[i]);
  456.                 dup_cookie(&p->curdir[i], &dir);
  457.             }
  458.         }
  459.         release_cookie(&dir);
  460.     }
  461.  
  462. /* free any file descriptors associated with shared text regions */
  463.     for (old = &text_reg; 0 != (stext = *old);) {
  464.         f = stext->f;
  465.         if (f->fc.dev == d) {
  466.             f->dev = NULL;
  467.             do_pclose(rootproc, f);
  468.             stext->f = 0;
  469. /* free region if unattached */
  470.             if (stext->text->links == 0xffff) {
  471.                 stext->text->links = 0;
  472.                 stext->text->mflags &= ~(M_SHTEXT|M_SHTEXT_T);
  473.                 free_region(stext->text);
  474.                 *old = stext->next;
  475.                 kfree(stext);
  476.                 continue;
  477.             }
  478. /* else clear `sticky bit' */
  479.             stext->text->mflags &= ~M_SHTEXT_T;
  480.         }
  481.         old = &stext->next;
  482.     }
  483. }
  484.  
  485. /*
  486.  * check for media change: if the drive has changed, call changedrv to
  487.  * invalidate any open files and file handles associated with it, and
  488.  * call the file system's media change routine.
  489.  * returns: 0 if no change, 1 if change, negative number for error
  490.  */
  491.  
  492. int
  493. disk_changed(d)
  494.     int d;
  495. {
  496.     short r;
  497.     FILESYS *fs;
  498.     static char tmpbuf[8192];
  499.  
  500. /* for now, only check BIOS devices */
  501.     if (d < 0 || d >= NUM_DRIVES)
  502.         return 0;
  503. /* watch out for aliased drives */
  504.     if (aliasdrv[d]) {
  505.         d = aliasdrv[d] - 1;
  506.         if (d < 0 || d >= NUM_DRIVES)
  507.             return 0;
  508.     }
  509.  
  510. /* has the drive been initialized yet? If not, then initialize it and return
  511.  * "no change"
  512.  */
  513.     fs = drives[d];
  514.     if (!fs) {
  515.         TRACE(("drive %c not yet initialized", d+'A'));
  516.         changedrv(d);
  517.         return 0;
  518.     }
  519.  
  520. /* We have to do this stuff no matter what, because someone may have installed
  521.  * vectors to force a media change...
  522.  * PROBLEM: AHDI may get upset if the drive isn't valid.
  523.  * SOLUTION: don't change the default PSEUDODRIVES setting!
  524.  */
  525.  
  526. TRACE(("calling mediach(%d)",d));
  527.     r = (int)mediach(d);
  528. TRACE(("mediach(%d) == %d", d, r));
  529.  
  530.     if (r < 0) {
  531. /* KLUDGE: some .XFS drivers don't install BIOS vectors, and so we'll
  532.  * always get EUNDEV back from them. This isn't recommended (since there
  533.  * are other programs than MiNT that may ask for BIOS functions from
  534.  * any installed drives). This is a temporary work-around until those
  535.  * .XFSes are changed to either install BIOS vectors or to use the
  536.  * new U: Dcntl() calls to install themselves.
  537.  * Note that EUNDEV must be tested for drives A-C, or else booting may
  538.  * not work properly.
  539.  */
  540.         if (d > 2 && r == EUNDEV)
  541.             return 0;    /* assume no change */
  542.         else
  543.             return r;
  544.     }
  545.     if (r == 1) {        /* drive _may_ have changed */
  546.         r = rwabs(0, tmpbuf, 1, 0, d, 0L);    /* check the BIOS */
  547.         if (r != E_CHNG) {            /* nope, no change */
  548.             TRACE(("rwabs returned %d", r));
  549.             return (r < 0) ? r : 0;
  550.         }
  551.         r = 2;            /* drive was definitely changed */
  552.     }
  553.     if (r == 2) {
  554.         TRACE(("definite media change"));
  555.         fs = drives[d];        /* get filesystem associated with drive */
  556.         if ((*fs->dskchng)(d)) { /* does the fs agree that it changed? */
  557.             drives[d] = 0;
  558.             changedrv(d);    /* yes -- do the change */
  559.             return 1;
  560.         }
  561.     }
  562.     return 0;
  563. }
  564.  
  565. /*
  566.  * routines for parsing path names
  567.  */
  568.  
  569. #define DIRSEP(p) ((p) == '\\')
  570.  
  571. /*
  572.  * relpath2cookie converts a TOS file name into a file cookie representing
  573.  * the directory the file resides in, and a character string representing
  574.  * the name of the file in that directory. The character string is
  575.  * copied into the "lastname" array. If lastname is NULL, then the cookie
  576.  * returned actually represents the file, instead of just the directory
  577.  * the file is in.
  578.  *
  579.  * note that lastname, if non-null, should be big enough to contain all the
  580.  * characters in "path", since if the file system doesn't want the kernel
  581.  * to do path name parsing we may end up just copying path to lastname
  582.  * and returning the current or root directory, as appropriate
  583.  *
  584.  * "relto" is the directory relative to which the search should start.
  585.  * if you just want the current directory, use path2cookie instead.
  586.  *
  587.  */
  588.  
  589. #define MAX_LINKS 4
  590.  
  591. long
  592. relpath2cookie(relto, path, lastname, res, depth)
  593.     fcookie *relto;
  594.     const char *path;
  595.     char *lastname;
  596.     fcookie *res;
  597.     int depth;
  598. {
  599.     fcookie dir;
  600.     int drv;
  601.     int len;
  602.     char c, *s;
  603.     XATTR xattr;
  604.     static char newpath[16] = "U:\\DEV\\";
  605.     char temp2[PATH_MAX];
  606.     char linkstuff[PATH_MAX];
  607.     long r;
  608.  
  609. /* dolast: 0 == return a cookie for the directory the file is in
  610.  *         1 == return a cookie for the file itself, don't follow links
  611.  *       2 == return a cookie for whatever the file points at
  612.  */
  613.     int dolast = 0;
  614.     int i = 0;
  615.  
  616.     if (!lastname) {
  617.         dolast = 1;
  618.         lastname = temp2;
  619.     } else if (lastname == follow_links) {
  620.         dolast = 2;
  621.         lastname = temp2;
  622.     }
  623.  
  624.     *lastname = 0;
  625.  
  626. PATH2COOKIE_DB(("relpath2cookie(%s, dolast=%d, depth=%d)", path, dolast, depth));
  627.  
  628.     if (depth > MAX_LINKS) {
  629.         DEBUG(("Too many symbolic links"));
  630.         return ELOOP;
  631.     }
  632. /* special cases: CON:, AUX:, etc. should be converted to U:\DEV\CON,
  633.  * U:\DEV\AUX, etc.
  634.  */
  635.     if (strlen(path) == 4 && path[3] == ':') {
  636.         strncpy(newpath+7, path, 3);
  637.         path = newpath;
  638.     }
  639.  
  640. /* first, check for a drive letter */
  641. /* BUG: a '\' at the start of a symbolic link is relative to the current
  642.  * drive of the process, not the drive the link is located on
  643.  */
  644.     if (path[1] == ':') {
  645.         c = path[0];
  646.         if (c >= 'a' && c <= 'z')
  647.             drv = c - 'a';
  648.         else if (c >= 'A' && c <= 'Z')
  649.             drv = c - 'A';
  650.         else
  651.             goto nodrive;
  652.         path += 2;
  653.         i = 1;        /* remember that we saw a drive letter */
  654.     } else {
  655. nodrive:
  656.         drv = curproc->curdrv;
  657.     }
  658.  
  659. /* see if the path is rooted from '\\' */
  660.     if (DIRSEP(*path)) {
  661.         while(DIRSEP(*path))path++;
  662.         dup_cookie(&dir, &curproc->root[drv]);
  663.     } else {
  664.         if (i)    {    /* an explicit drive letter was given */
  665.             dup_cookie(&dir, &curproc->curdir[drv]);
  666.         }
  667.         else
  668.             dup_cookie(&dir, relto);
  669.     }
  670.  
  671.     if (!dir.fs) {
  672.         changedrv(dir.dev);
  673.         dup_cookie(&dir, &curproc->root[drv]);
  674.     }
  675.  
  676.     if (!dir.fs) {
  677.         DEBUG(("path2cookie: no file system: returning EDRIVE"));
  678.         return EDRIVE;
  679.     }
  680.  
  681.     /* here's where we come when we've gone across a mount point */
  682.     
  683. restart_mount:
  684.  
  685.     if (!*path) {        /* nothing more to do */
  686. PATH2COOKIE_DB(("relpath2cookie: no more path, returning 0"));
  687.         *res = dir;
  688.         return 0;
  689.     }
  690.  
  691. /* see if there has been a disk change; if so, return E_CHNG.
  692.  * path2cookie will restart the search automatically; other functions
  693.  * that call relpath2cookie directly will have to fail gracefully
  694.  */
  695.     if ((r = disk_changed(dir.dev)) != 0) {
  696.         release_cookie(&dir);
  697.         if (r > 0) r = E_CHNG;
  698. PATH2COOKIE_DB(("relpath2cookie: returning %d", r));
  699.         return r;
  700.     }
  701.  
  702.  
  703.     if (dir.fs->fsflags & FS_KNOPARSE) {
  704.         if (!dolast) {
  705. PATH2COOKIE_DB(("fs is a KNOPARSE, nothing to do"));
  706.             strncpy(lastname, path, PATH_MAX-1);
  707.             lastname[PATH_MAX - 1] = 0;
  708.             r = 0;
  709.             *res = dir;
  710.         } else {
  711. PATH2COOKIE_DB(("fs is a KNOPARSE, calling lookup"));
  712.             r = (*dir.fs->lookup)(&dir, path, res);
  713.             if (r == EMOUNT) {    /* hmmm... a ".." at a mount point, maybe */
  714.                 fcookie mounteddir;
  715.                 r = (*dir.fs->root)(dir.dev, &mounteddir);
  716.                 if (r == 0 && drv == UNIDRV) {
  717.                     if (dir.fs == mounteddir.fs &&
  718.                         dir.index == mounteddir.index &&
  719.                         dir.dev == mounteddir.dev) {
  720.                         release_cookie(&dir);
  721.                         release_cookie(&mounteddir);
  722.                         dup_cookie(&dir, &curproc->root[UNIDRV]);
  723.                         TRACE(("path2cookie: restarting from mount point"));
  724.                         goto restart_mount;
  725.                     }
  726.                 } else {
  727.                     if (r == 0)
  728.                         release_cookie(&mounteddir);
  729.                     r = 0;
  730.                 }
  731.             }
  732.             release_cookie(&dir);
  733.         }
  734.         PATH2COOKIE_DB(("relpath2cookie: returning %ld", r));
  735.         return r;
  736.     }
  737.  
  738.  
  739. /* parse all but (possibly) the last component of the path name */
  740. /* rules here: at the top of the loop, &dir is the cookie of
  741.  * the directory we're in now, xattr is its attributes, and res is unset
  742.  * at the end of the loop, &dir is unset, and either r is nonzero
  743.  * (to indicate an error) or res is set to the final result
  744.  */
  745.     r = (dir.fs->getxattr)(&dir, &xattr);
  746.     if (r) {
  747.         DEBUG(("couldn't get directory attributes"));
  748.         release_cookie(&dir);
  749.         return EINTRN;
  750.     }
  751.  
  752.     while (*path) {
  753.  
  754.     /* now we must have a directory, since there are more things in the path */
  755.         if ((xattr.mode & S_IFMT) != S_IFDIR) {
  756. PATH2COOKIE_DB(("relpath2cookie: not a directory, returning EPTHNF"));
  757.             release_cookie(&dir);
  758.             r = EPTHNF;
  759.             break;
  760.         }
  761.     /* we must also have search permission for the directory */
  762.         if (denyaccess(&xattr, S_IXOTH)) {
  763.             DEBUG(("search permission in directory denied"));
  764.             release_cookie(&dir);
  765.             r = EPTHNF;
  766.             break;
  767.         }
  768.  
  769.     /* if there's nothing left in the path, we can break here */
  770.         if (!*path) {
  771. PATH2COOKIE_DB(("relpath2cookie: no more path, breaking (1)"));
  772.             *res = dir;
  773.             break;
  774.         }
  775.     /* next, peel off the next name in the path */
  776.         len = 0;
  777.         s = lastname;
  778.         c = *path;
  779.         while (c && !DIRSEP(c)) {
  780.             if (len++ < PATH_MAX)
  781.                 *s++ = c;
  782.             c = *++path;
  783.         }
  784.         *s = 0;
  785.  
  786.     /* if there are no more names in the path, and we don't want
  787.      * to actually look up the last name, then we're done
  788.      */
  789.         if (dolast == 0 && !*path) {
  790.             *res = dir;
  791. PATH2COOKIE_DB(("relpath2cookie: no more path, breaking (2)"));
  792.             break;
  793.         }
  794.  
  795.  
  796.     /* 
  797.      * skip trailing slashes
  798.      */
  799.         while (DIRSEP(*path)) path++;
  800.  
  801. PATH2COOKIE_DB(("relpath2cookie: looking up [%s]", lastname));
  802.  
  803.         r = (*dir.fs->lookup)(&dir, lastname, res);
  804.         if (r == EMOUNT) {
  805.             fcookie mounteddir;
  806.             r = (*dir.fs->root)(dir.dev, &mounteddir);
  807.             if (r == 0 && drv == UNIDRV) {
  808.                 if (samefile(&dir, &mounteddir)) {
  809.                     release_cookie(&dir);
  810.                     release_cookie(&mounteddir);
  811.                     dup_cookie(&dir, &curproc->root[UNIDRV]);
  812.                     TRACE(("path2cookie: restarting from mount point"));
  813.                     goto restart_mount;
  814.                 } else if (r == 0) {
  815.                     r = EINTRN;
  816.                     release_cookie(&mounteddir);
  817.                     release_cookie(&dir);
  818.                     break;
  819.                 }
  820.             } else if (r == 0) {
  821.                 release_cookie(&mounteddir);
  822.             } else {
  823.                 release_cookie(&dir);
  824.                 break;
  825.             }
  826.         } else if (r) {
  827.             if (r == EFILNF && *path) {
  828.             /* the "file" we didn't find was treated as a directory */
  829.                 r = EPTHNF;
  830.             }
  831.             release_cookie(&dir);
  832.             break;
  833.         }
  834.  
  835.     /* check for a symbolic link */
  836.         r = (res->fs->getxattr)(res, &xattr);
  837.         if (r != 0) {
  838.             DEBUG(("path2cookie: couldn't get file attributes"));
  839.             release_cookie(&dir);
  840.             release_cookie(res);
  841.             break;
  842.         }
  843.  
  844.     /* if the file is a link, and we're following links, follow it */
  845.         if ( (xattr.mode & S_IFMT) == S_IFLNK && (*path || dolast > 1)) {
  846.             r = (res->fs->readlink)(res, linkstuff, PATH_MAX);
  847.             release_cookie(res);
  848.             if (r) {
  849.                 DEBUG(("error reading symbolic link"));
  850.                 release_cookie(&dir);
  851.                 break;
  852.             }
  853.             r = relpath2cookie(&dir, linkstuff, follow_links, res,
  854.                         depth+1);
  855.             release_cookie(&dir);
  856.             if (r) {
  857.                 DEBUG(("error following symbolic link"));
  858.                 break;
  859.             }
  860.             dir = *res;
  861.             (void)(res->fs->getxattr)(res, &xattr);
  862.         } else {
  863.             release_cookie(&dir);
  864.             dir = *res;
  865.         }
  866.     }
  867.  
  868.     PATH2COOKIE_DB(("relpath2cookie: returning %ld", r));
  869.     return r;
  870. }
  871.  
  872. #define MAX_TRYS 8
  873.  
  874. long
  875. path2cookie(path, lastname, res)
  876.     const char *path;
  877.     char *lastname;
  878.     fcookie *res;
  879. {
  880.     fcookie *dir;
  881.     long r;
  882. /* AHDI sometimes will keep insisting that a media change occured;
  883.  * we limit the number of retrys to avoid hanging the system
  884.  */
  885.     int trycnt = 0;
  886.  
  887.     dir = &curproc->curdir[curproc->curdrv];
  888.  
  889.     do {
  890.         r = relpath2cookie(dir, path, lastname, res, 0);
  891.         if (r == E_CHNG)
  892.             DEBUG(("path2cookie: restarting due to media change"));
  893.     } while (r == E_CHNG && trycnt++ < MAX_TRYS);
  894.  
  895.     return r;
  896. }
  897.  
  898. /*
  899.  * release_cookie: tell the file system owner that a cookie is no
  900.  * longer in use by the kernel
  901.  */
  902. void
  903. release_cookie(fc)
  904.     fcookie *fc;
  905. {
  906.     FILESYS *fs;
  907.  
  908.     if (fc) {
  909.         fs = fc->fs;
  910.         if (fs && fs->release) {
  911.             (void)(*fs->release)(fc);
  912.         }
  913.     }
  914. }
  915.  
  916. /*
  917.  * Make a new cookie (newc) which is a duplicate of the old cookie
  918.  * (oldc). This may be something the file system is interested in,
  919.  * so we give it a chance to do the duplication; if it doesn't
  920.  * want to, we just copy.
  921.  */
  922.  
  923. void
  924. dup_cookie(newc, oldc)
  925.     fcookie *newc, *oldc;
  926. {
  927.     FILESYS *fs = oldc->fs;
  928.  
  929.     if (fs && fs->release && fs->dupcookie) {
  930.         (void)(*fs->dupcookie)(newc, oldc);
  931.     } else {
  932.         *newc = *oldc;
  933.     }
  934. }
  935.  
  936. /*
  937.  * new_fileptr, dispose_fileptr: allocate (deallocate) a file pointer
  938.  */
  939.  
  940. FILEPTR *
  941. new_fileptr()
  942. {
  943.     FILEPTR *f;
  944.  
  945.     if ((f = flist) != 0) {
  946.         flist = f->next;
  947.         f->next = 0;
  948.         return f;
  949.     }
  950.     f = kmalloc(SIZEOF(FILEPTR));
  951.     if (!f) {
  952.         FATAL("new_fileptr: out of memory");
  953.     }
  954.     else {
  955.         f->next = 0;
  956.     }
  957.     return f;
  958. }
  959.  
  960. void
  961. dispose_fileptr(f)
  962.     FILEPTR *f;
  963. {
  964.     if (f->links != 0) {
  965.         FATAL("dispose_fileptr: f->links == %d", f->links);
  966.     }
  967.     f->next = flist;
  968.     flist = f;
  969. }
  970.  
  971. /*
  972.  * denyshare(list, f): "list" points at the first FILEPTR in a
  973.  * chained list of open FILEPTRS referring to the same file;
  974.  * f is a newly opened FILEPTR. Every FILEPTR in the given list is
  975.  * checked to see if its "open" mode (in list->flags) is compatible with
  976.  * the open mode in f->flags. If not (for example, if f was opened with
  977.  * a "read" mode and some other file has the O_DENYREAD share mode),
  978.  * then 1 is returned. If all the open FILEPTRs in the list are
  979.  * compatible with f, then 0 is returned.
  980.  * This is not as complicated as it sounds. In practice, just keep a
  981.  * list of open FILEPTRs attached to each file, and put something like
  982.  *     if (denyshare(thisfile->openfileptrlist, newfileptr))
  983.  *        return EACCDN;
  984.  * in the device open routine.
  985.  */
  986.  
  987. int ARGS_ON_STACK 
  988. denyshare(list, f)
  989.     FILEPTR *list, *f;
  990. {
  991.     int newrm, newsm;    /* new read and sharing mode */
  992.     int oldrm, oldsm;    /* read and sharing mode of already opened file */
  993.     extern MEMREGION *tofreed;
  994.     MEMREGION *m = tofreed;
  995.     int i;
  996.  
  997.     newrm = f->flags & O_RWMODE;
  998.     newsm = f->flags & O_SHMODE;
  999.  
  1000. /*
  1001.  * O_EXEC gets treated the same as O_RDONLY for our purposes
  1002.  */
  1003.     if (newrm == O_EXEC) newrm = O_RDONLY;
  1004.  
  1005. /* New meaning for O_COMPAT: deny write access to all _other_
  1006.  * processes.
  1007.  */
  1008.  
  1009.     for ( ; list; list = list->next) {
  1010.         oldrm = list->flags & O_RWMODE;
  1011.         if (oldrm == O_EXEC) oldrm = O_RDONLY;
  1012.         oldsm = list->flags & O_SHMODE;
  1013.         if (oldsm == O_DENYW || oldsm == O_DENYRW) {
  1014.              if (newrm != O_RDONLY) {
  1015. /* conflict because of unattached shared text region? */
  1016.                 if (!m && NULL != (m = find_text_seg(list))) {
  1017.                     if (m->links == 0xffff)
  1018.                         continue;
  1019.                     m = 0;
  1020.                 }
  1021.                 DEBUG(("write access denied"));
  1022.                 return 1;
  1023.             }
  1024.         }
  1025.         if (oldsm == O_DENYR || oldsm == O_DENYRW) {
  1026.             if (newrm != O_WRONLY) {
  1027.                 DEBUG(("read access denied"));
  1028.                 return 1;
  1029.             }
  1030.         }
  1031.         if (newsm == O_DENYW || newsm == O_DENYRW) {
  1032.             if (oldrm != O_RDONLY) {
  1033.                 DEBUG(("couldn't deny writes"));
  1034.                 return 1;
  1035.             }
  1036.         }
  1037.         if (newsm == O_DENYR || newsm == O_DENYRW) {
  1038.             if (oldrm != O_WRONLY) {
  1039.                 DEBUG(("couldn't deny reads"));
  1040.                 return 1;
  1041.             }
  1042.         }
  1043. /* If either sm == O_COMPAT, then we check to make sure
  1044.    that the file pointers are owned by the same process (O_COMPAT means
  1045.    "deny writes to any other processes"). This isn't quite the same
  1046.    as the Atari spec, which says O_COMPAT means "deny access to other
  1047.    processes." We should fix the spec.
  1048.  */
  1049.         if ((newsm == O_COMPAT && newrm != O_RDONLY && oldrm != O_RDONLY) ||
  1050.             (oldsm == O_COMPAT && newrm != O_RDONLY)) {
  1051.             for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  1052.                 if (curproc->handle[i] == list)
  1053.                     goto found;
  1054.             }
  1055.         /* old file pointer is not open by this process */
  1056.             DEBUG(("O_COMPAT file was opened for writing by another process"));
  1057.             return 1;
  1058.         found:
  1059.             ;    /* everything is OK */
  1060.         }
  1061.     }
  1062. /* cannot close shared text regions file here... have open do it. */
  1063.     if (m)
  1064.         tofreed = m;
  1065.     return 0;
  1066. }
  1067.  
  1068. /*
  1069.  * denyaccess(XATTR *xattr, unsigned perm): checks to see if the access
  1070.  * specified by perm (which must be some combination of S_IROTH, S_IWOTH,
  1071.  * and S_IXOTH) should be granted to the current process
  1072.  * on a file with the given extended attributes. Returns 0 if access
  1073.  * by the current process is OK, 1 if not.
  1074.  */
  1075.  
  1076. int
  1077. ngroupmatch(group)
  1078.     int group;
  1079. {
  1080.     int i;
  1081.  
  1082.     for (i=0; i<curproc->ngroups; i++)
  1083.         if (curproc->ngroup[i] == group)
  1084.             return 1;
  1085.  
  1086.     return 0;
  1087. }
  1088.  
  1089. int
  1090. denyaccess(xattr, perm)
  1091.     XATTR *xattr;
  1092.     unsigned perm;
  1093. {
  1094.     unsigned mode;
  1095.  
  1096. /* the super-user can do anything! */
  1097.     if (curproc->euid == 0)
  1098.         return 0;
  1099.  
  1100.     mode = xattr->mode;
  1101.     if (curproc->euid == xattr->uid)
  1102.         perm = perm << 6;
  1103.     else if (curproc->egid == xattr->gid)
  1104.         perm = perm << 3;
  1105.     else if (ngroupmatch(xattr->gid))
  1106.         perm = perm << 3;
  1107.  
  1108.     if ((mode & perm) != perm) return 1;    /* access denied */
  1109.     return 0;
  1110. }
  1111.  
  1112. /*
  1113.  * Checks a lock against a list of locks to see if there is a conflict.
  1114.  * This is a utility to be used by file systems, somewhat like denyshare
  1115.  * above. Returns 0 if there is no conflict, or a pointer to the
  1116.  * conflicting LOCK structure if there is.
  1117.  *
  1118.  * Conflicts occur for overlapping locks if the process id's are
  1119.  * different and if at least one of the locks is a write lock.
  1120.  *
  1121.  * NOTE: we assume before being called that the locks have been converted
  1122.  * so that l_start is absolute. not relative to the current position or
  1123.  * end of file.
  1124.  */
  1125.  
  1126. LOCK * ARGS_ON_STACK 
  1127. denylock(list, lck)
  1128.     LOCK *list, *lck;
  1129. {
  1130.     LOCK *t;
  1131.     unsigned long tstart, tend;
  1132.     unsigned long lstart, lend;
  1133.     int pid = curproc->pid;
  1134.     int ltype;
  1135.  
  1136.     ltype = lck->l.l_type;
  1137.     lstart = lck->l.l_start;
  1138.  
  1139.     if (lck->l.l_len == 0)
  1140.         lend = 0xffffffffL;
  1141.     else
  1142.         lend = lstart + lck->l.l_len - 1;
  1143.  
  1144.     for (t = list; t; t = t->next) {
  1145.         tstart = t->l.l_start;
  1146.         if (t->l.l_len == 0)
  1147.             tend = 0xffffffffL;
  1148.         else
  1149.             tend = tstart + t->l.l_len - 1;
  1150.  
  1151.     /* look for overlapping locks */
  1152.         if (tstart <= lstart && tend >= lstart && t->l.l_pid != pid &&
  1153.             (ltype == F_WRLCK || t->l.l_type == F_WRLCK))
  1154.             break;
  1155.         if (lstart <= tstart && lend >= tstart && t->l.l_pid != pid &&
  1156.             (ltype == F_WRLCK || t->l.l_type == F_WRLCK))
  1157.             break;
  1158.     }
  1159.     return t;
  1160. }
  1161.  
  1162. /*
  1163.  * check to see that a file is a directory, and that write permission
  1164.  * is granted; return an error code, or 0 if everything is ok.
  1165.  */
  1166. long
  1167. dir_access(dir, perm)
  1168.     fcookie *dir;
  1169.     unsigned perm;
  1170. {
  1171.     XATTR xattr;
  1172.     long r;
  1173.  
  1174.     r = (*dir->fs->getxattr)(dir, &xattr);
  1175.     if (r) {
  1176.         DEBUG(("dir_access: file system returned %ld", r));
  1177.         return r;
  1178.     }
  1179.     if ( (xattr.mode & S_IFMT) != S_IFDIR ) {
  1180.         DEBUG(("file is not a directory"));
  1181.         return EPTHNF;
  1182.     }
  1183.     if (denyaccess(&xattr, perm)) {
  1184.         DEBUG(("no permission for directory"));
  1185.         return EACCDN;
  1186.     }
  1187.     return 0;
  1188. }
  1189.  
  1190. /*
  1191.  * returns 1 if the given name contains a wildcard character 
  1192.  */
  1193.  
  1194. int
  1195. has_wild(name)
  1196.     const char *name;
  1197. {
  1198.     char c;
  1199.  
  1200.     while ((c = *name++) != 0) {
  1201.         if (c == '*' || c == '?') return 1;
  1202.     }
  1203.     return 0;
  1204. }
  1205.  
  1206. /*
  1207.  * void copy8_3(dest, src): convert a file name (src) into DOS 8.3 format
  1208.  * (in dest). Note the following things:
  1209.  * if a field has less than the required number of characters, it is
  1210.  * padded with blanks
  1211.  * a '*' means to pad the rest of the field with '?' characters
  1212.  * special things to watch for:
  1213.  *    "." and ".." are more or less left alone
  1214.  *    "*.*" is recognized as a special pattern, for which dest is set
  1215.  *    to just "*"
  1216.  * Long names are truncated. Any extensions after the first one are
  1217.  * ignored, i.e. foo.bar.c -> foo.bar, foo.c.bar->foo.c.
  1218.  */
  1219.  
  1220. void
  1221. copy8_3(dest, src)
  1222.     char *dest;
  1223.     const char *src;
  1224. {
  1225.     char fill = ' ', c;
  1226.     int i;
  1227.  
  1228.     if (src[0] == '.') {
  1229.         if (src[1] == 0) {
  1230.             strcpy(dest, ".       .   ");
  1231.             return;
  1232.         }
  1233.         if (src[1] == '.' && src[2] == 0) {
  1234.             strcpy(dest, "..      .   ");
  1235.             return;
  1236.         }
  1237.     }
  1238.     if (src[0] == '*' && src[1] == '.' && src[2] == '*' && src[3] == 0) {
  1239.         dest[0] = '*';
  1240.         dest[1] = 0;
  1241.         return;
  1242.     }
  1243.  
  1244.     for (i = 0; i < 8; i++) {
  1245.         c = *src++;
  1246.         if (!c || c == '.') break;
  1247.         if (c == '*') {
  1248.             fill = c = '?';
  1249.         }
  1250.         *dest++ = toupper(c);
  1251.     }
  1252.     while (i++ < 8) {
  1253.         *dest++ = fill;
  1254.     }
  1255.     *dest++ = '.';
  1256.     i = 0;
  1257.     fill = ' ';
  1258.     while (c && c != '.')
  1259.         c = *src++;
  1260.  
  1261.     if (c) {
  1262.         for( ;i < 3; i++) {
  1263.             c = *src++;
  1264.             if (!c || c == '.') break;
  1265.             if (c == '*')
  1266.                 c = fill = '?';
  1267.             *dest++ = toupper(c);
  1268.         }
  1269.     }
  1270.     while (i++ < 3)
  1271.         *dest++ = fill;
  1272.     *dest = 0;
  1273. }
  1274.  
  1275. /*
  1276.  * int pat_match(name, patrn): returns 1 if "name" matches the template in
  1277.  * "patrn", 0 if not. "patrn" is assumed to have been expanded in 8.3
  1278.  * format by copy8_3; "name" need not be. Any '?' characters in patrn
  1279.  * will match any character in name. Note that if "patrn" has a '*' as
  1280.  * the first character, it will always match; this will happen only if
  1281.  * the original pattern (before copy8_3 was applied) was "*.*".
  1282.  *
  1283.  * BUGS: acts a lot like the silly TOS pattern matcher.
  1284.  */
  1285.  
  1286. int
  1287. pat_match(name, template)
  1288.     const char *name, *template;
  1289. {
  1290.     register char *s, c;
  1291.     char expname[TOS_NAMELEN+1];
  1292.  
  1293.     if (*template == '*') return 1;
  1294.     copy8_3(expname, name);
  1295.  
  1296.     s = expname;
  1297.     while ((c = *template++) != 0) {
  1298.         if (c != *s && c != '?')
  1299.             return 0;
  1300.         s++;
  1301.     }
  1302.     return 1;
  1303. }
  1304.  
  1305. /*
  1306.  * int samefile(fcookie *a, fcookie *b): returns 1 if the two cookies
  1307.  * refer to the same file or directory, 0 otherwise
  1308.  */
  1309.  
  1310. int
  1311. samefile(a, b)
  1312.     fcookie *a, *b;
  1313. {
  1314.     if (a->fs == b->fs && a->dev == b->dev && a->index == b->index)
  1315.         return 1;
  1316.     return 0;
  1317. }
  1318.